home *** CD-ROM | disk | FTP | other *** search
Text File | 1993-08-01 | 28.2 KB | 1,061 lines | [TEXT/R*ch] |
- # This is a shell archive. Save it in a file, remove anything before
- # this line, and then unpack it by entering "sh file". Note, it may
- # create directories; files and directories will be owned by you and
- # have default permissions.
- #
- # This archive contains:
- #
- # READ.ME
- # install.bsd
- # spkr.7
- # Makefile
- # spkr.c
- # spkr.h
- # interp.c
- # Files
- # Install
- # Master
- # Name
- # Node
- # Remove
- # Size
- # System
- # playtest
- #
- echo x - READ.ME
- sed 's/^X//' >READ.ME << 'END-of-READ.ME'
- X Console Speaker Driver Package (v1.1)
- X
- X by Eric S. Raymond (esr@snark.thyrsus.com)
- X
- XThis package gives 80386 machines running SVr3.2 or later the ability to play
- Xtunes on the console speaker. It has been extended to 386BSD (and possibly
- XBSDI) by Andrew A. Chernov, and to SCO UNIX 3.2.4 (and possibly other VPIX
- Xsystems) by Andreas Arens.
- X
- XThe following files are contained in the kit:
- X
- XDocumentation and examples:
- XREAD.ME -- this file
- Xspeaker.7 -- man page for the driver
- Xplaytest -- test script exercising familiar tunes
- X
- XInstallable driver kit parts, for SVr3.2 or later:
- XFiles -- list of driver package file locations
- XInstall -- installation script for driver kit
- XMaster -- mdevice entry for speaker driver
- XName -- name entry foe speaker driver
- XNode -- /dev node specification file
- XRemove -- Driver removal script
- XSize -- installation size data
- XSystem -- sdevice entry for speaker driver
- X
- XDriver source code, for SVr3.2 or later and 386BSD:
- XMakefile -- Makefile for driver code
- Xspkr.c -- the driver source
- Xspeaker.h -- ioctl interface file
- X
- XCommon source code:
- Xinterp.c -- play string interpretation code
- X
- XFor SVr3.2 or later, simply type `make' and wait. Then type ./Install
- Xand follow its instructions. You will have to install the man pages by hand.
- XBe aware that the speaker.7 man page uses tbl(1) constructs.
- X
- XFor 386BSD, follow the installation instructions in install.bsd.
- X
- XFor SCO UNIX 3.2.4, no new kernel drivers are needed, and you need only
- Xcopy interp.c to your src directory and proceed with making NetHack, with
- XVPIX_MUSIC set in unixconf.h.
- X
- XInteresting tunes mailed to the author will be periodically posted in batches
- Xand added to the test script for future versions.
- X
- X Revision notes
- X
- X1.1 -- fixed minor bug in M[LSN] interpretation, added octave-tracking.
- X Tweaked the playtest examples.
- END-of-READ.ME
- echo x - install.bsd
- sed 's/^X//' >install.bsd << 'END-of-install.bsd'
- XCopy spkr.c and interp.c to /sys/i386/isa
- XCopy spkr.h to /sys/sys
- X
- X-----------------------------------------------------------------------------
- X
- XFile /sys/i386/conf/YOUR_MACHINE_NAME
- Xadd following line:
- X
- Xpseudo-device speaker
- X
- X-----------------------------------------------------------------------------
- X
- XFile /sys/i386/conf/files.i386
- Xadd following line:
- X
- Xi386/isa/spkr.c optional speaker
- X
- X-----------------------------------------------------------------------------
- X
- XFile /sys/i386/i386/conf.c
- X[major number 20 (hex) is registered for spkr driver, don't change it]
- Xadd following code:
- X
- X#include "speaker.h"
- X#if NSPEAKER > 0
- Xint spkropen(),spkrclose(),spkrwrite(),spkrioctl();
- X#else
- X#define spkropen enxio
- X#define spkrclose enxio
- X#define spkrwrite enxio
- X#define spkrioctl enxio
- X#endif
- X ...
- X
- Xstruct cdevsw cdevsw[] =
- X{
- X ...
- X
- X { spkropen, spkrclose, enxio, spkrwrite, /*20*/
- X spkrioctl, enxio, enxio, NULL,
- X enxio, enxio, enxio },
- X ...
- X
- X-----------------------------------------------------------------------------
- X
- XMake corresponding device:
- X
- X mknod /dev/speaker c 32 0
- X
- X[major number 32 (20 hex) is registered for spkr driver, don't change it]
- X
- X-----------------------------------------------------------------------------
- X
- XGo to /sys/i386/conf and type
- X config YOUR_MACHINE_NAME
- Xthen go to /sys/compile/YOUR_MACHINE_NAME and type
- X make depend
- X make
- X
- END-of-install.bsd
- echo x - spkr.7
- sed 's/^X//' >spkr.7 << 'END-of-spkr.7'
- X.TH SPKR 7
- X.SH NAME
- Xspkr \- console speaker device driver
- X.SH DESCRIPTION
- XThe speaker device driver allows applications to control the PC console
- Xspeaker on an IBM-PC-compatible machine running UNIX.
- X.PP
- XOnly one process may have this device open at any given time; open() and
- Xclose() are used to lock and relinquish it. An attempt to open() when
- Xanother process has the device locked will return -1 with an EBUSY error
- Xindication. Writes to the device are interpreted as 'play strings' in a
- Xsimple ASCII melody notation. An ioctl() for tone generation at arbitrary
- Xfrequencies is also supported.
- X.PP
- XSound-generation does \fInot\fR monopolize the processor; in fact, the driver
- Xspends most of its time sleeping while the PC hardware is emitting
- Xtones. Other processes may emit beeps while the driver is running.
- X.PP
- XApplications may call ioctl() on a speaker file descriptor to control the
- Xspeaker driver directly; definitions for the ioctl() interface are in
- Xsys/spkr.h. The tone_t structure used in these calls has two fields,
- Xspecifying a frequency (in hz) and a duration (in 1/100ths of a second).
- XA frequency of zero is interpreted as a rest.
- X.PP
- XAt present there are two such ioctls. SPKRTONE accepts a pointer to a
- Xsingle tone structure as third argument and plays it. SPKRTUNE accepts a
- Xpointer to the first of an array of tone structures and plays them in
- Xcontinuous sequence; this array must be terminated by a final member with
- Xa zero duration.
- X.PP
- XThe play-string language is modelled on the PLAY statement conventions of
- XIBM BASIC 2.0. The MB, MF and X primitives of PLAY are not useful in a UNIX
- Xenvironment and are omitted. The `octave-tracking' feature is also new.
- X.PP
- XThere are 84 accessible notes numbered 1-83 in 7 octaves, each running from
- XC to B, numbered 0-6; the scale is equal-tempered A440 and octave 3 starts
- Xwith middle C. By default, the play function emits half-second notes with the
- Xlast 1/16th second being `rest time'.
- X.PP
- XPlay strings are interpreted left to right as a series of play command groups;
- Xletter case is ignored. Play command groups are as follows:
- X.PP
- XCDEFGAB -- letters A through G cause the corresponding note to be played in the
- Xcurrent octave. A note letter may optionally be followed by an \fIaccidental
- Xsign\fR, one of # + or -; the first two of these cause it to be sharped one
- Xhalf-tone, the last causes it to be flatted one half-tone. It may also be
- Xfollowed by a time value number and by sustain dots (see below). Time values
- Xare interpreted as for the L command below;.
- X.PP
- XO <n> -- if <n> is numeric, this sets the current octave. <n> may also be one
- Xof 'L' or 'N' to enable or disable octave-tracking (it is disabled by default).
- XWhen octave-tracking is on, interpretation of a pair of letter notes will
- Xchange octaves if necessary in order to make the smallest possible jump between
- Xnotes. Thus "olbc" will be played as "olb>c", and "olcb" as "olc<b". Octave
- Xlocking is disabled for one letter note following by >, < and O[0123456].
- X.PP
- X> -- bump the current octave up one.
- X.PP
- X< -- drop the current octave down one.
- X.PP
- XN <n> -- play note n, n being 1 to 84 or 0 for a rest of current time value.
- XMay be followedv by sustain dots.
- X.PP
- XL <n> -- sets the current time value for notes. The default is L4, quarter
- Xnotes. The lowest possible value is 1; values up to 64 are accepted. L1 sets
- Xwhole notes, L2 sets half notes, L4 sets quarter notes, etc..
- X.PP
- XP <n> -- pause (rest), with <n> interpreted as for L. May be followed by
- Xsustain dots. May also be written '~'.
- X.PP
- XT <n> -- Sets the number of quarter notes per minute; default is 120. Musical
- Xnames for common tempi are:
- X
- X.TS
- Xa a a.
- X Tempo Beats Per Minute
- Xvery slow Larghissimo
- X Largo 40-60
- X Larghetto 60-66
- X Grave
- X Lento
- X Adagio 66-76
- Xslow Adagietto
- X Andante 76-108
- Xmedium Andantino
- X Moderato 108-120
- Xfast Allegretto
- X Allegro 120-168
- X Vivace
- X Veloce
- X Presto 168-208
- Xvery fast Prestissimo
- X.TE
- X.PP
- XM[LNS] -- set articulation. MN (N for normal) is the default; the last 1/8th of
- Xthe note's value is rest time. You can set ML for legato (no rest space) or
- XMS (staccato) 1/4 rest space.
- X.PP
- XNotes (that is, CDEFGAB or N command character groups) may be followed by
- Xsustain dots. Each dot causes the note's value to be lengthened by one-half
- Xfor each one. Thus, a note dotted once is held for 3/2 of its undotted value;
- Xdotted twice, it is held 9/4, and three times would give 27/8.
- X.PP
- XWhitespace in play strings is simply skipped and may be used to separate
- Xmelody sections.
- X.SH BUGS
- XDue to roundoff in the pitch tables and slop in the tone-generation and timer
- Xhardware (neither of which was designed for precision), neither pitch accuracy
- Xnor timings will be mathematically exact. There is no volume control.
- X.PP
- XIn play strings which are very long (longer than your system's physical I/O
- Xblocks) note suffixes or numbers may occasionally be parsed incorrectly due
- Xto crossing a block boundary.
- X.SH FILES
- X/dev/speaker -- speaker device file
- X.SH AUTHOR
- XEric S. Raymond (esr@snark.thyrsus.com) Feb 1990
- END-of-spkr.7
- echo x - Makefile
- sed 's/^X//' >Makefile << 'END-of-Makefile'
- X#
- X# Speaker driver package makefile
- X#
- XCFLAGS = -I. -O # -DDEBUG
- XLDFLAGS = -s
- X
- Xall: Driver.o
- X
- Xinstall:
- X ./Install
- X
- XDriver.o: spkr.c
- X $(CC) $(CFLAGS) -c spkr.c
- X mv spkr.o Driver.o
- X
- Xclean:
- X rm -f Driver.o *~ speaker.shar
- X
- XDSP = Files Install Master Name Node Remove Size System
- Xshar:
- X shar READ.ME install.bsd spkr.7 Makefile spkr.[ch] \
- X interp.c $(DSP) playtest >speaker.shar
- END-of-Makefile
- echo x - spkr.c
- sed 's/^X//' >spkr.c << 'END-of-spkr.c'
- X/*
- X * spkr.c -- device driver for console speaker on 80386
- X *
- X * v1.1 by Eric S. Raymond (esr@snark.thyrsus.com) Feb 1990
- X * modified for 386bsd by Andrew A. Chernov <ache@astral.msk.su>
- X */
- X
- X#ifdef __386BSD__
- X#include "speaker.h"
- X#endif
- X#if !defined(__386BSD__) || (NSPEAKER > 0)
- X
- X#ifdef __386BSD__
- X#include "types.h"
- X#include "param.h"
- X#include "errno.h"
- X#include "buf.h"
- X#include "uio.h"
- X
- X#define CADDR caddr_t
- X#define err_ret(x) return(x)
- X#else /* SYSV */
- X#include <sys/types.h>
- X#include <sys/param.h>
- X#include <sys/dir.h>
- X#include <sys/signal.h>
- X#include <sys/errno.h>
- X#include <sys/ioctl.h>
- X#include <sys/user.h>
- X#include <sys/sysmacros.h>
- X#include <limits.h>
- X
- X#define CADDR char *
- X#define err_ret(x) u.u_error = (x)
- X#endif
- X
- X#include "spkr.h"
- X
- X/**************** MACHINE DEPENDENT PART STARTS HERE *************************
- X *
- X * This section defines a function tone() which causes a tone of given
- X * frequency and duration from the 80x86's console speaker.
- X * Another function endtone() is defined to force sound off, and there is
- X * also a rest() entry point to do pauses.
- X *
- X * Audible sound is generated using the Programmable Interval Timer (PIT) and
- X * Programmable Peripheral Interface (PPI) attached to the 80x86's speaker. The
- X * PPI controls whether sound is passed through at all; the PIT's channel 2 is
- X * used to generate clicks (a square wave) of whatever frequency is desired.
- X *
- X * The non-BSD code requires SVr3.2-compatible inb(), outb(), timeout(),
- X * sleep(), and wakeup().
- X */
- X
- X/*
- X * PIT and PPI port addresses and control values
- X *
- X * Most of the magic is hidden in the TIMER_PREP value, which selects PIT
- X * channel 2, frequency LSB first, square-wave mode and binary encoding.
- X * The encoding is as follows:
- X *
- X * +----------+----------+---------------+-----+
- X * | 1 0 | 1 1 | 0 1 1 | 0 |
- X * | SC1 SC0 | RW1 RW0 | M2 M1 M0 | BCD |
- X * +----------+----------+---------------+-----+
- X * Counter Write Mode 3 Binary
- X * Channel 2 LSB first, (Square Wave) Encoding
- X * MSB second
- X */
- X#define PPI 0x61 /* port of Programmable Peripheral Interface */
- X#define PPI_SPKR 0x03 /* turn these PPI bits on to pass sound */
- X#define PIT_CTRL 0x43 /* PIT control address */
- X#define PIT_COUNT 0x42 /* PIT count address */
- X#define PIT_MODE 0xB6 /* set timer mode for sound generation */
- X
- X/*
- X * Magic numbers for timer control.
- X */
- X#define TIMER_CLK 1193180L /* corresponds to 18.2 MHz tick rate */
- X
- Xstatic int endtone()
- X/* turn off the speaker, ending current tone */
- X{
- X wakeup((CADDR)endtone);
- X outb(PPI, inb(PPI) & ~PPI_SPKR);
- X}
- X
- Xstatic void tone(hz, ticks)
- X/* emit tone of frequency hz for given number of ticks */
- Xunsigned int hz, ticks;
- X{
- X unsigned int divisor = TIMER_CLK / hz;
- X int sps;
- X
- X#ifdef DEBUG
- X printf("tone: hz=%d ticks=%d\n", hz, ticks);
- X#endif /* DEBUG */
- X
- X /* set timer to generate clicks at given frequency in Hertz */
- X#ifdef __386BSD__
- X sps = spltty();
- X#else
- X sps = spl5();
- X#endif
- X outb(PIT_CTRL, PIT_MODE); /* prepare timer */
- X outb(PIT_COUNT, (unsigned char) divisor); /* send lo byte */
- X outb(PIT_COUNT, (divisor >> 8)); /* send hi byte */
- X splx(sps);
- X
- X /* turn the speaker on */
- X outb(PPI, inb(PPI) | PPI_SPKR);
- X
- X /*
- X * Set timeout to endtone function, then give up the timeslice.
- X * This is so other processes can execute while the tone is being
- X * emitted.
- X */
- X timeout((CADDR)endtone, (CADDR)NULL, ticks);
- X sleep((CADDR)endtone, PZERO - 1);
- X}
- X
- Xstatic int endrest()
- X/* end a rest */
- X{
- X wakeup((CADDR)endrest);
- X}
- X
- Xstatic void rest(ticks)
- X/* rest for given number of ticks */
- Xint ticks;
- X{
- X /*
- X * Set timeout to endrest function, then give up the timeslice.
- X * This is so other processes can execute while the rest is being
- X * waited out.
- X */
- X#ifdef DEBUG
- X printf("rest: %d\n", ticks);
- X#endif /* DEBUG */
- X timeout((CADDR)endrest, (CADDR)NULL, ticks);
- X sleep((CADDR)endrest, PZERO - 1);
- X}
- X
- X#include "interp.c" /* playinit() and playstring() */
- X
- X/******************* UNIX DRIVER HOOKS BEGIN HERE **************************
- X *
- X * This section implements driver hooks to run playstring() and the tone(),
- X * endtone(), and rest() functions defined above. For non-BSD systems,
- X * SVr3.2-compatible copyin() is also required.
- X */
- X
- Xstatic int spkr_active; /* exclusion flag */
- X#ifdef __386BSD__
- Xstatic struct buf *spkr_inbuf; /* incoming buf */
- X#endif
- X
- Xint spkropen(dev)
- Xdev_t dev;
- X{
- X#ifdef DEBUG
- X printf("spkropen: entering with dev = %x\n", dev);
- X#endif /* DEBUG */
- X
- X if (minor(dev) != 0)
- X err_ret(ENXIO);
- X else if (spkr_active)
- X err_ret(EBUSY);
- X else
- X {
- X playinit();
- X#ifdef __386BSD__
- X spkr_inbuf = geteblk(DEV_BSIZE);
- X#endif
- X spkr_active = 1;
- X }
- X#ifdef __386BSD__
- X return(0);
- X#endif
- X}
- X
- X#ifdef __386BSD__
- Xint spkrwrite(dev, uio)
- Xstruct uio *uio;
- X#else
- Xint spkrwrite(dev)
- X#endif
- Xdev_t dev;
- X{
- X#ifdef __386BSD__
- X register unsigned n;
- X char *cp;
- X int error;
- X#endif
- X#ifdef DEBUG
- X#ifdef __386BSD__
- X printf("spkrwrite: entering with dev = %x, count = %d\n",
- X dev, uio->uio_resid);
- X#else
- X printf("spkrwrite: entering with dev = %x, u.u_count = %d\n",
- X dev, u.u_count);
- X#endif
- X#endif /* DEBUG */
- X
- X if (minor(dev) != 0)
- X err_ret(ENXIO);
- X else
- X {
- X#ifdef __386BSD__
- X n = MIN(DEV_BSIZE, uio->uio_resid);
- X cp = spkr_inbuf->b_un.b_addr;
- X error = uiomove(cp, n, uio);
- X if (!error)
- X playstring(cp, n);
- X return(error);
- X#else
- X char bfr[STD_BLK];
- X
- X copyin(u.u_base, bfr, u.u_count);
- X playstring(bfr, u.u_count);
- X u.u_base += u.u_count;
- X u.u_count = 0;
- X#endif
- X }
- X}
- X
- Xint spkrclose(dev)
- Xdev_t dev;
- X{
- X#ifdef DEBUG
- X printf("spkrclose: entering with dev = %x\n", dev);
- X#endif /* DEBUG */
- X
- X if (minor(dev) != 0)
- X err_ret(ENXIO);
- X else
- X {
- X endtone();
- X#ifdef __386BSD__
- X brelse(spkr_inbuf);
- X#endif
- X spkr_active = 0;
- X }
- X#ifdef __386BSD__
- X return(0);
- X#endif
- X}
- X
- Xint spkrioctl(dev, cmd, cmdarg)
- Xdev_t dev;
- Xint cmd;
- XCADDR cmdarg;
- X{
- X#ifdef DEBUG
- X printf("spkrioctl: entering with dev = %x, cmd = %x\n", dev, cmd);
- X#endif /* DEBUG */
- X
- X if (minor(dev) != 0)
- X err_ret(ENXIO);
- X else if (cmd == SPKRTONE)
- X {
- X tone_t *tp = (tone_t *)cmdarg;
- X
- X if (tp->frequency == 0)
- X rest(tp->duration);
- X else
- X tone(tp->frequency, tp->duration);
- X }
- X else if (cmd == SPKRTUNE)
- X {
- X#ifdef __386BSD__
- X tone_t *tp = (tone_t *)(*(caddr_t *)cmdarg);
- X tone_t ttp;
- X int error;
- X
- X for (; ; tp++) {
- X error = copyin(tp, &ttp, sizeof(tone_t));
- X if (error)
- X return(error);
- X if (ttp.duration == 0)
- X break;
- X if (ttp.frequency == 0)
- X rest(ttp.duration);
- X else
- X tone(ttp.frequency, ttp.duration);
- X }
- X#else
- X tone_t *tp = (tone_t *)cmdarg;
- X
- X for (; tp->duration; tp++)
- X if (tp->frequency == 0)
- X rest(tp->duration);
- X else
- X tone(tp->frequency, tp->duration);
- X#endif
- X }
- X else
- X err_ret(EINVAL);
- X#ifdef __386BSD__
- X return(0);
- X#endif
- X}
- X
- X#endif /* !defined(__386BSD__) || (NSPEAKER > 0) */
- X/* spkr.c ends here */
- END-of-spkr.c
- echo x - spkr.h
- sed 's/^X//' >spkr.h << 'END-of-spkr.h'
- X/*
- X * spkr.h -- interface definitions for speaker ioctl()
- X *
- X * v1.1 by Eric S. Raymond (esr@snark.thyrsus.com) Feb 1990
- X * modified for 386bsd by Andrew A. Chernov <ache@astral.msk.su>
- X */
- X
- X#ifndef _SPKR_H_
- X#define _SPKR_H_
- X
- X#ifdef __386BSD__
- X#ifndef KERNEL
- X#include <sys/ioctl.h>
- X#else
- X#include "ioctl.h"
- X#endif
- X
- X#define SPKRTONE _IOW('S', 1, tone_t) /* emit tone */
- X#define SPKRTUNE _IO('S', 2) /* emit tone sequence*/
- X#else /* SYSV */
- X#define SPKRIOC ('S'<<8)
- X#define SPKRTONE (SPKRIOC|1) /* emit tone */
- X#define SPKRTUNE (SPKRIOC|2) /* emit tone sequence*/
- X#endif
- X
- Xtypedef struct
- X{
- X int frequency; /* in hertz */
- X int duration; /* in 1/100ths of a second */
- X}
- Xtone_t;
- X
- X#endif /* _SPKR_H_ */
- X/* spkr.h ends here */
- END-of-spkr.h
- echo x - interp.c
- sed 's/^X//' >interp.c << 'END-of-interp.c'
- X/*
- X * interp.c -- device driver for console speaker on 80386
- X *
- X * v1.1 by Eric S. Raymond (esr@snark.thyrsus.com) Feb 1990
- X *
- X * this is the part of the code common to all 386 UNIX OSes
- X *
- X * playinit() and playstring() are called from the appropriate driver
- X */
- X
- X#ifdef __386BSD__
- X#include "param.h"
- X#else
- X#include <sys/param.h>
- X#endif
- X
- X#ifndef HZ
- X#define HZ 60
- X#endif
- X
- X
- X/**************** PLAY STRING INTERPRETER BEGINS HERE **********************
- X *
- X * Play string interpretation is modelled on IBM BASIC 2.0's PLAY statement;
- X * M[LNS] are missing and the ~ synonym and octave-tracking facility is added.
- X * Requires tone(), rest(), and endtone(). String play is not interruptible
- X * except possibly at physical block boundaries.
- X */
- X
- Xtypedef int bool;
- X#define TRUE 1
- X#define FALSE 0
- X
- X#define toupper(c) ((c) - ' ' * (((c) >= 'a') && ((c) <= 'z')))
- X#define isdigit(c) (((c) >= '0') && ((c) <= '9'))
- X#define dtoi(c) ((c) - '0')
- X
- Xstatic int octave; /* currently selected octave */
- Xstatic int whole; /* whole-note time at current tempo, in ticks */
- Xstatic int value; /* whole divisor for note time, quarter note = 1 */
- Xstatic int fill; /* controls spacing of notes */
- Xstatic bool octtrack; /* octave-tracking on? */
- Xstatic bool octprefix; /* override current octave-tracking state? */
- X
- X/*
- X * Magic number avoidance...
- X */
- X#define SECS_PER_MIN 60 /* seconds per minute */
- X#define WHOLE_NOTE 4 /* quarter notes per whole note */
- X#define MIN_VALUE 64 /* the most we can divide a note by */
- X#define DFLT_VALUE 4 /* default value (quarter-note) */
- X#define FILLTIME 8 /* for articulation, break note in parts */
- X#define STACCATO 6 /* 6/8 = 3/4 of note is filled */
- X#define NORMAL 7 /* 7/8ths of note interval is filled */
- X#define LEGATO 8 /* all of note interval is filled */
- X#define DFLT_OCTAVE 4 /* default octave */
- X#define MIN_TEMPO 32 /* minimum tempo */
- X#define DFLT_TEMPO 120 /* default tempo */
- X#define MAX_TEMPO 255 /* max tempo */
- X#define NUM_MULT 3 /* numerator of dot multiplier */
- X#define DENOM_MULT 2 /* denominator of dot multiplier */
- X
- X/* letter to half-tone: A B C D E F G */
- Xstatic int notetab[8] = {9, 11, 0, 2, 4, 5, 7};
- X
- X/*
- X * This is the American Standard A440 Equal-Tempered scale with frequencies
- X * rounded to nearest integer. Thank Goddess for the good ol' CRC Handbook...
- X * our octave 0 is standard octave 2.
- X */
- X#define OCTAVE_NOTES 12 /* semitones per octave */
- Xstatic int pitchtab[] =
- X{
- X/* C C# D D# E F F# G G# A A# B*/
- X/* 0 */ 65, 69, 73, 78, 82, 87, 93, 98, 103, 110, 117, 123,
- X/* 1 */ 131, 139, 147, 156, 165, 175, 185, 196, 208, 220, 233, 247,
- X/* 2 */ 262, 277, 294, 311, 330, 349, 370, 392, 415, 440, 466, 494,
- X/* 3 */ 523, 554, 587, 622, 659, 698, 740, 784, 831, 880, 932, 988,
- X/* 4 */ 1047, 1109, 1175, 1245, 1319, 1397, 1480, 1568, 1661, 1760, 1865, 1975,
- X/* 5 */ 2093, 2217, 2349, 2489, 2637, 2794, 2960, 3136, 3322, 3520, 3729, 3951,
- X/* 6 */ 4186, 4435, 4698, 4978, 5274, 5588, 5920, 6272, 6644, 7040, 7459, 7902,
- X};
- X
- Xstatic void playinit()
- X{
- X octave = DFLT_OCTAVE;
- X whole = (HZ * SECS_PER_MIN * WHOLE_NOTE) / DFLT_TEMPO;
- X fill = NORMAL;
- X value = DFLT_VALUE;
- X octtrack = FALSE;
- X octprefix = TRUE; /* act as though there was an initial O(n) */
- X}
- X
- Xstatic void playtone(pitch, value, sustain)
- X/* play tone of proper duration for current rhythm signature */
- Xint pitch, value, sustain;
- X{
- X register int sound, silence, snum = 1, sdenom = 1;
- X
- X /* this weirdness avoids floating-point arithmetic */
- X for (; sustain; sustain--)
- X {
- X snum *= NUM_MULT;
- X sdenom *= DENOM_MULT;
- X }
- X
- X if (pitch == -1)
- X rest(whole * snum / (value * sdenom));
- X else
- X {
- X sound = (whole * snum) / (value * sdenom)
- X - (whole * (FILLTIME - fill)) / (value * FILLTIME);
- X silence = whole * (FILLTIME-fill) * snum / (FILLTIME * value * sdenom);
- X
- X#ifdef DEBUG
- X printf("playtone: pitch %d for %d ticks, rest for %d ticks\n",
- X pitch, sound, silence);
- X#endif /* DEBUG */
- X
- X tone(pitchtab[pitch], sound);
- X if (fill != LEGATO)
- X rest(silence);
- X }
- X}
- X
- Xstatic int abs(n)
- Xint n;
- X{
- X if (n < 0)
- X return(-n);
- X else
- X return(n);
- X}
- X
- Xstatic void playstring(cp, slen)
- X/* interpret and play an item from a notation string */
- Xchar *cp;
- Xsize_t slen;
- X{
- X int pitch, lastpitch = OCTAVE_NOTES * DFLT_OCTAVE;
- X
- X#define GETNUM(cp, v) for(v=0; isdigit(cp[1]) && slen > 0; ) \
- X {v = v * 10 + (*++cp - '0'); slen--;}
- X for (; slen--; cp++)
- X {
- X int sustain, timeval, tempo;
- X register char c = toupper(*cp);
- X
- X#ifdef DEBUG
- X printf("playstring: %c (%x)\n", c, c);
- X#endif /* DEBUG */
- X
- X switch (c)
- X {
- X case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G':
- X
- X /* compute pitch */
- X pitch = notetab[c - 'A'] + octave * OCTAVE_NOTES;
- X
- X /* this may be followed by an accidental sign */
- X if (cp[1] == '#' || cp[1] == '+')
- X {
- X ++pitch;
- X ++cp;
- X slen--;
- X }
- X else if (cp[1] == '-')
- X {
- X --pitch;
- X ++cp;
- X slen--;
- X }
- X
- X /*
- X * If octave-tracking mode is on, and there has been no octave-
- X * setting prefix, find the version of the current letter note
- X * closest to the last regardless of octave.
- X */
- X if (octtrack && !octprefix)
- X {
- X if (abs(pitch-lastpitch) > abs(pitch+OCTAVE_NOTES-lastpitch))
- X {
- X ++octave;
- X pitch += OCTAVE_NOTES;
- X }
- X
- X if (abs(pitch-lastpitch) > abs((pitch-OCTAVE_NOTES)-lastpitch))
- X {
- X --octave;
- X pitch -= OCTAVE_NOTES;
- X }
- X }
- X octprefix = FALSE;
- X lastpitch = pitch;
- X
- X /* ...which may in turn be followed by an override time value */
- X GETNUM(cp, timeval);
- X if (timeval <= 0 || timeval > MIN_VALUE)
- X timeval = value;
- X
- X /* ...and/or sustain dots */
- X for (sustain = 0; cp[1] == '.'; cp++)
- X {
- X slen--;
- X sustain++;
- X }
- X
- X /* time to emit the actual tone */
- X playtone(pitch, timeval, sustain);
- X break;
- X
- X case 'O':
- X if (cp[1] == 'N' || cp[1] == 'n')
- X {
- X octprefix = octtrack = FALSE;
- X ++cp;
- X slen--;
- X }
- X else if (cp[1] == 'L' || cp[1] == 'l')
- X {
- X octtrack = TRUE;
- X ++cp;
- X slen--;
- X }
- X else
- X {
- X GETNUM(cp, octave);
- X if (octave >= sizeof(pitchtab) / OCTAVE_NOTES)
- X octave = DFLT_OCTAVE;
- X octprefix = TRUE;
- X }
- X break;
- X
- X case '>':
- X if (octave < sizeof(pitchtab) / OCTAVE_NOTES - 1)
- X octave++;
- X octprefix = TRUE;
- X break;
- X
- X case '<':
- X if (octave > 0)
- X octave--;
- X octprefix = TRUE;
- X break;
- X
- X case 'N':
- X GETNUM(cp, pitch);
- X for (sustain = 0; cp[1] == '.'; cp++)
- X {
- X slen--;
- X sustain++;
- X }
- X playtone(pitch - 1, value, sustain);
- X break;
- X
- X case 'L':
- X GETNUM(cp, value);
- X if (value <= 0 || value > MIN_VALUE)
- X value = DFLT_VALUE;
- X break;
- X
- X case 'P':
- X case '~':
- X /* this may be followed by an override time value */
- X GETNUM(cp, timeval);
- X if (timeval <= 0 || timeval > MIN_VALUE)
- X timeval = value;
- X for (sustain = 0; cp[1] == '.'; cp++)
- X {
- X slen--;
- X sustain++;
- X }
- X playtone(-1, timeval, sustain);
- X break;
- X
- X case 'T':
- X GETNUM(cp, tempo);
- X if (tempo < MIN_TEMPO || tempo > MAX_TEMPO)
- X tempo = DFLT_TEMPO;
- X whole = (HZ * SECS_PER_MIN * WHOLE_NOTE) / tempo;
- X break;
- X
- X case 'M':
- X if (cp[1] == 'N' || cp[1] == 'n')
- X {
- X fill = NORMAL;
- X ++cp;
- X slen--;
- X }
- X else if (cp[1] == 'L' || cp[1] == 'l')
- X {
- X fill = LEGATO;
- X ++cp;
- X slen--;
- X }
- X else if (cp[1] == 'S' || cp[1] == 's')
- X {
- X fill = STACCATO;
- X ++cp;
- X slen--;
- X }
- X break;
- X }
- X }
- X}
- END-of-interp.c
- echo x - Files
- sed 's/^X//' >Files << 'END-of-Files'
- X/usr/include/sys/spkr.h
- END-of-Files
- echo x - Install
- sed 's/^X//' >Install << 'END-of-Install'
- X#
- X# Speaker driver installation script
- X#
- XTMP=/tmp/speaker.err
- XERR1=" Errors have been written to the file $TMP."
- XERR2=" The Speaker Driver software was not installed."
- X
- Xecho "Installing Speaker Driver Software Package"
- X
- X/etc/conf/bin/idcheck -p speaker 2>$TMP
- Xif [ $? != 0 ]
- Xthen
- X echo "The speaker package is already at least partly installed.
- X Removing the old version now..."
- X /etc/conf/bin/idinstall -d speaker
- Xfi
- X
- X/etc/conf/bin/idinstall -a -k speaker 2>>$TMP
- Xif [ $? != 0 ]
- Xthen
- X message "There was an error during package installation. $ERR1 $ERR2"
- X exit 1
- Xfi
- X
- X/etc/conf/bin/idbuild 2>>$TMP
- Xif [ $? != 0 ]
- Xthen
- X message "There was an error during kernel reconfiguration. $ERR1 $ERR2"
- X exit 1
- Xfi
- X
- Xrm -f $TMP
- X
- Xcp spkr.h /usr/include/sys/spkr.h
- X
- Xecho "Performing shutdown..."
- Xcd /; exec /etc/shutdown -g0 -y
- END-of-Install
- echo x - Master
- sed 's/^X//' >Master << 'END-of-Master'
- Xspeaker ocwi iocH spkr 0 0 1 1 -1
- END-of-Master
- echo x - Name
- sed 's/^X//' >Name << 'END-of-Name'
- X386 UNIX Speaker Device Driver Package
- END-of-Name
- echo x - Node
- sed 's/^X//' >Node << 'END-of-Node'
- Xspeaker speaker c 0
- END-of-Node
- echo x - Remove
- sed 's/^X//' >Remove << 'END-of-Remove'
- X#
- X# Speaker driver remove script
- X#
- XTMP=/tmp/speaker.err
- XRERR="Errors have been written to the file $TMP."
- X
- Xecho "Removing Speaker Driver Software Package"
- X
- X/etc/conf/bin/idinstall -d speaker 2>$TMP
- Xif [ $? != 0 ]
- Xthen
- X message "There was an error during package removal. $RERR"
- X exit 1
- Xfi
- X
- X/etc/conf/bin/idbuild 2>>$TMP
- Xif [ $? != 0 ]
- Xthen
- X message "There was an error during kernel reconfiguration. $RERR"
- X exit 1
- Xfi
- X
- Xrm -f /dev/speaker $TMP /usr/include/sys/spkr.h
- X
- Xexit 0
- END-of-Remove
- echo x - Size
- sed 's/^X//' >Size << 'END-of-Size'
- XROOT=1400
- XUSR=100
- END-of-Size
- echo x - System
- sed 's/^X//' >System << 'END-of-System'
- Xspeaker Y 1 0 0 0 0 0 0 0
- END-of-System
- echo x - playtest
- sed 's/^X//' >playtest << 'END-of-playtest'
- X:
- X# Test script for the speaker driver
- X#
- X# v1.0 by Eric S. Raymond (Feb 1990)
- X# modified for 386bsd by Andrew A. Chernov <ache@astral.msk.su>
- X#
- Xreveille="t255l8c.f.afc~c.f.afc~c.f.afc.f.a..f.~c.f.afc~c.f.afc~c.f.afc~c.f.."
- Xcontact="<cd<a#~<a#>f"
- Xdance="t240<cfcfgagaa#b#>dc<a#a.~fg.gaa#.agagegc.~cfcfgagaa#b#>dc<a#a.~fg.gga.agfgfgf."
- Xloony="t255cf8f8edc<a.>~cf8f8edd#e.~ce8cdce8cd.<a>c8c8c#def8af8."
- X
- Xcase $1 in
- Xreveille) echo $reveille >/dev/speaker;;
- Xcontact) echo $contact >/dev/speaker;;
- Xdance) echo $dance >/dev/speaker;;
- Xloony) echo $loony >/dev/speaker;;
- X*)
- X echo "No such tune. Available tunes are:"
- X echo
- X echo "reveille -- Reveille"
- X echo "contact -- Contact theme from Close Encounters"
- X echo "dance -- Lord of the Dance (aka Simple Gifts)"
- X echo "loony -- Loony Toons theme"
- X ;;
- Xesac
- END-of-playtest
- exit
-